#pragma once

#include <iostream>
#include <pthread.h>
#include <fstream>
#include <vector>
#include <sstream>
#include <unordered_map>
#include "Log.hpp"
#include "Sock.hpp"
#include "Daemon.hpp"

const int serverport = 8080;
const std::string sep = "\r\n";
const std::string spacesep = " ";
const std::string path = "./wwwroot";
const std::string homage = "index.html";

class Httpserver;

struct ThreadData{
	int sockfd;
	Httpserver* htp;
};

class HttpRequest{
public:
	HttpRequest()
	{}
	void Deserializee(std::string req)
	{
		while(true)
		{
			int pos = req.find(sep);
			if(pos == std::string::npos) break;
			std::string tmp = req.substr(0,pos);
			if(tmp.empty()) break;
			req_header.push_back(tmp);
			req.erase(0,pos + sep.size());
		}
		text = req;
	}
	void spltheader()
	{
		// //方法1
		// std::string res = req_header[0];
		// int left = res.find(spacesep);
		// if(left == std::string::npos) return;
		// method = res.substr(0,left);
		// int right = res.rfind(spacesep);
		// if(right == std::string::npos) return;
		// if(left == right) return;
		// http_version = res.substr(right+1);
		// url = res.substr(left + 1,right - left - 1);

		//方法2
		std::stringstream req(req_header[0]);
		req >> method >> url >> http_version;
		file_path = path;
		if(url == "/" || url == "/index.html"){
			file_path += "/";
			file_path += homage;
		}
		else file_path += url;

		int pos = file_path.rfind(".");
		if(pos == std::string::npos) suffix = ".html";
		else{
			suffix = file_path.substr(pos);
		}
	}
	void DebugPrint()
    {
        for(auto &line : req_header)
        {
            std::cout << "--------------------------------" << std::endl;
            std::cout << line << "\n\n";
        }

        std::cout << "method: " << method << std::endl;
        std::cout << "url: " << url << std::endl;
        std::cout << "http_version: " << http_version << std::endl;
        std::cout << "file_path: " << file_path << std::endl;
        std::cout << text << std::endl;
    }
	std::string Getpath()
	{
		return file_path;
	}
	std::string Getsuffix()
	{
		return suffix;
	}
private:
	std::vector<std::string> req_header;
	std::string text;

	std::string url;
	std::string http_version;
	std::string method;
	std::string file_path;

	std::string suffix;   //记录文件后缀
};

class Httpserver{
public:
	// void Lock()
	// {
	// 	pthread_mutex_lock(&mutex);
	// }
	// void Unlock()
	// {
	// 	pthread_mutex_unlock(&mutex);
	// }
	Httpserver(const uint16_t& p = serverport):port(p)
	{
		// pthread_mutex_init(&mutex,nullptr);
		// pthread_cond_init(&cond,nullptr);
		content_type[".html"] = "text/html";
		content_type[".jpg"] = "image/jpeg";
	}
	void Init()
	{
		listensockfd.Socket();
		listensockfd.Bind(port);
		listensockfd.Listen();
		lg(Info,"Init socket success");
	}
	void start()
	{
		// Daemon();
		while(true)
		{
			std::string clientip;
			uint16_t clientport;
			int sockfd = listensockfd.Accept(&clientip,&clientport);
			ThreadData td;
			td.sockfd = sockfd;
			td.htp = this;
			pthread_t tid;
			pthread_create(&tid,nullptr,threadrun,&td);
		}
		listensockfd.Close();
	}
	static std::string ReadHtmlcontent(const std::string& str)
	{
		std::ifstream ifs(str,std::ios_base::in | std::ios_base::binary);
		if(ifs.is_open()){
			ifs.seekg(0,std::ios::end);
			auto len = ifs.tellg();
			ifs.seekg(0,std::ios::beg);                   ////  ----------  坑 ------------- 必须要用二进制读写，因为图片的读取是用的二进制
			std::string ret;
			ret.resize(len);
			ifs.read((char*)ret.c_str(),len);
			// std::string line;
			// while(getline(ifs,line)){
			// 	ret += line;
			// }
			ifs.close();
			return ret;
		}
		else{
			return "";
		}
	}
	std::string Findsuf(const std::string& s)
	{
		auto it = content_type.find(s);
		if(it == content_type.end()) return content_type[".html"];
		return content_type[s];
	}
	static void* threadrun(void* args)
	{
		pthread_detach(pthread_self());
		ThreadData* td = static_cast<ThreadData*>(args);
		char buffer[10240];
		// td->htp->Lock();
		int n = recv(td->sockfd,buffer,sizeof(buffer)-1,0);
		if(n > 0){
			buffer[n] = 0;
			lg(Info,"Get a request,request:%s",buffer);
			bool flag = true;
			HttpRequest hq;
			hq.Deserializee(buffer);
			hq.spltheader();
			hq.DebugPrint();
			// std::string text = "<html><body><h3>Hello World</h3></body></html>";
			std::string text = ReadHtmlcontent(hq.Getpath());
			if(text.empty()){
				flag = false;
				std::string newpath = path + "/";
				newpath += "err.html";
				text = ReadHtmlcontent(newpath);
			}
			std::string response_line;
			if(flag) response_line = "HTTP/1.1 200 OK\r\n";
			else response_line = "HTTP/1.1 404 not found\r\n";
			// response_line = "HTTP/1.1 302 found\r\n";
			std::string response_header = "content-length: ";
			response_header += std::to_string(text.size());
			response_header += "\r\n";
			response_header += "content-type: ";
			response_header += td->htp->Findsuf(hq.Getsuffix());
			response_header += "\r\n";										///         犯了一个饭桶错误，忘记协议要求加\r\n了，牢记
			response_header += "Set-Cookie: name=haha&&passwd=mmsss";
			response_header += "\r\n";
			response_header += "Set-Cookie: view=hello.html";
			response_header += "\r\n";
			// response_header += "Location: https://www.qq.com\r\n";
			std::string blankline = "\r\n";
			std::string response = response_line;
			response += response_header;
			response += blankline;
			response += text;

			send(td->sockfd,response.c_str(),response.size(),0);

		}
		// td->htp->Unlock();
		close(td->sockfd);
		return nullptr;
	}
private:
	Sock listensockfd;
	uint16_t port;
	std::unordered_map<std::string,std::string> content_type;
	// pthread_mutex_t mutex;
	// pthread_cond_t cond;
};
